from pathlib import Path
import random
import time
import re
import os
from pathlib import Path
import itertools
import shutil

from bs4 import BeautifulSoup
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.common.by import By
import pyautogui

from browser import Browser


class Parser(Browser):

    """ Этот класс представляет парсер """

    def __init__(self, data, proxy_list=None):

        self.display_browser = data[0]
        self.proxy_list = proxy_list
        self.link_to_main_page = 'https://www.artstation.com/'
        self.email = data[2]
        self.password = data[3]
        self.link_to_video = data[4]


    def wait(self, f=2, b=3.5):

        """ Чуть-чуть подождать """

        number = random.uniform(f, b)
        print(f'Ждем {number}\n')
        time.sleep(number)


    def convert_to_bs(self, browser):

        """ Получаем объект BeautifulSoup """

        html_source = browser.page_source
        page = BeautifulSoup(html_source, 'lxml')

        return page


    def get_saved_page(self, file_name):

        """ Открываем сохраненную страницу для парсинга и возвращаем ее """

        folder = Path('saved_html/')
        page = folder/file_name

        with open(page, 'r', encoding='utf-8') as file:

            text = file.read()
            page = BeautifulSoup(text, 'lxml')

            return page


    def get_configured_browser(self, proxy=None):

        """ Получаем настроенный браузер """

        if proxy:  # Если необходимо делать запрос через прокси

            for proxy in self.proxy_list:

                browser = self.get_browser(self.display_browser, proxy)

                return browser

        else:  # Если прокси не используюется

            return self.get_browser(self.display_browser, proxy)


    def start_video(self, browser):

        """ Запускаем видео """

        try:

            start_button = browser.find_element(
                By.XPATH,
                '//button[@title="Play Video"]'
            )
            start_button.click()

            print('Запустили видео')

        except:

            print('Видео запустилось автоматически')


    def get_current_video_time(self, browser):

        """ Получаем текущее время видео """

        page = self.convert_to_bs(browser)

        current_time = page.find('div', {'class': 'vjs-current-time-display'}).text
        current_time = ''.join(re.findall(r'\d+:\d+', current_time))

        return current_time


    def rewind(self, browser):

        """ Перематываем видео в начало """

        while True:

            current_time = self.get_current_video_time(browser)

            if '0:00' in current_time:

                break

            else:

                pyautogui.press('left')
                time.sleep(.3)


    def get_duration_video(self, browser):

        """ Получаем длительность видео """

        page = self.convert_to_bs(browser)

        duration_video = page.find('div', {'class': 'vjs-duration-display'}).text
        duration_video = ''.join(re.findall(r'\d+:\d+', duration_video))

        return duration_video


    def get_subtitles_and_timecodes(self, browser):

        """ Получаем субтитры и их таймкод """

        def get_subtitles(browser):

            """ Получаем субтитры """

            try:

                subtitles = browser.find_element(
                    By.XPATH,
                    '//div[@class="theoplayer-texttracks"]//span'
                )
                subtitles = subtitles.text
                print(subtitles)

                return subtitles

            except Exception as e:

                print('Субтитров нет')
                return 'Субтитров нет'


        # ВЫШЕ ОПРЕДЕЛЕНИЕ ФУНКЦИЙ

        subtitles_and_timecodes = []

        while True:

            subtitles = get_subtitles(browser)
            duration_video = self.get_duration_video(browser)
            current_time = self.get_current_video_time(browser)
            subtitles_and_timecodes.append([subtitles, current_time])

            #if '0:30' in current_time: break
            if not('0:00' in duration_video) and current_time == duration_video: break

            time.sleep(.1)

        return subtitles_and_timecodes


    def converting_data(self, data):

        """ Преобразовываем данные в нужный вид """

        done = []
        result = []
        result.append([data[0]])

        for item in data:

            if item[0] == result[-1][-1][0]:

                result[-1].append(item)

            else:

                result.append([item])

        for item in result:

            if item[0][0] == 'Субтитров нет': continue

            text = item[0][0]
            beginning_subtitles = item[0][-1]
            end_subtitles = item[-1][-1]

            entry = [text, beginning_subtitles, end_subtitles]
            done.append(entry)

        return done


    def add_data_to_file(self, video_title, data):

        """ Добавляем данные в файл """

#        if part_name:
#
#            try:
#
#                os.mkdir(f'./subtitles_of_all_videos/{part_name}')
#
#            except:
#
#                pass
#
#            with open(f'subtitles_of_all_videos/{part_name}/{video_title}.txt', 'w') as file:
#
#                for i, item in enumerate(data, 1):
#
#                    entry = f'\n{item[1]} --> {item[2]}\n{item[0]}\n'
#                    print(entry)
#                    file.write(entry)

        with open(f'subtitles_of_all_videos/{video_title}.txt', 'w') as file:

            for i, item in enumerate(data, 1):

                entry = f'\n{item[1]} --> {item[2]}\n{item[0]}\n'
                print(entry)
                file.write(entry)


    def login_to_site(self, browser):

        """ Авторизоваться на сайте """

        def open_authorization_form(browser):

            """ Открываем форму авторизации """

            authorization_form_button = browser.find_element(
                By.XPATH,
                '//a[@data-target="#login-modal"]'
            )
            authorization_form_button.click()


        def enter_email(browser):

            """ Указываем почту """

            email_field = browser.find_element(
                By.XPATH,
                '//input[@id="user_email"]'
            )
            email_field.click()
            email_field.clear()
            email_field.send_keys(self.email)

            self.wait(.5, .8)


        def enter_password(browser):

            """ Указываем пароль пароль """

            password_field = browser.find_element(
                By.XPATH,
                '//input[@id="user_password"]'
            )
            password_field.click()
            password_field.clear()
            password_field.send_keys(self.password)

            self.wait(.5, .8)


        def click_login_button(browser):

            """ Нажимаем кнопку войти """

            login_button = browser.find_element(
                By.XPATH,
                '//input[@id="user_password"]/../following-sibling::div/button'
            )
            login_button.click()


        # ВЫШЕ ОПРЕДЕЛЕНИЕ ФУНКЦИЙ

        open_authorization_form(browser)
        enter_email(browser)
        enter_password(browser)
        click_login_button(browser)

        time.sleep(5)

        print('Авторизовались на сайте')


    def get_video_title(self, browser):

        """ Получаем название видео """

        title = browser.find_element(
            By.XPATH,
            '//h1'
        ).text
        title = ' '.join(re.findall(r'\w+', title))

        return title


    def get_browser_with_authorized_user(self):

        """ Получаем браузер с авторизированным пользователем и указанным видео"""

        def close_possible_windows_that_appear(browser):

            """ Закрываем возможные появляющиеся окна """

            try:

                window = browser.find_element(
                    By.XPATH,
                    '//div[@class="modal-content"]/div/button[@class="close"]'
                )
                window.click()

            except Exception as e:

                print(e)


        # ВЫШЕ ОПРЕДЕЛЕНИЕ ФУНКЦИЙ

        browser = self.get_configured_browser()      # Получаем браузер
        browser.get(self.link_to_main_page)          # Открываем главную страницу сайта
        browser.maximize_window()

        browser.implicitly_wait(10)

        close_possible_windows_that_appear(browser)  # Закрываем появляющиеся окна

        self.login_to_site(browser)                  # Авторизируемся на сайте
        browser.get(self.link_to_video)              # Переходим к начальному видео

        return browser


    def translate_subtitles(self, data):

        """ Переводим субтитры """

        def add_label_to_subtitles(data):

            """ Добавляем метку к субтитрам """

            result = []

            for subtitles in data:

                subtitles.append('ё')
                result.append(subtitles)


        def prepare_subtitles_for_translation(data):

            """ Подгатавливаем субтитры для перевода """

            temp_result = []

            for subtitles in data:

                entry = ' '.join(subtitles)
                temp_result.append(entry)

            result = ' '.join(temp_result)

            return result


        # ВЫШЕ ОПРЕДЕЛЕНИЕ ФУНКЦИЙ

        converted_subtitles = add_label_to_subtitles(data)
        prepared_subtitles_for_translation = prepare_subtitles_for_translation(converted_subtitles)

        print('prepared_subtitles_for_translation')
        print(prepared_subtitles_for_translation)
        print(len(prepared_subtitles_for_translation))
        print('prepared_subtitles_for_translation')


    def move_to_element(self, browser, element):

        """ Перемещаемся к элементу """

        action = ActionChains(browser)
        action.move_to_element(element)
        action.perform()


    def get_list_videos_to_watch(self, browser):

        """ Получаем список видео у которых нужно собирать субтитры """

        def work_with_section_divided_into_parts(browser, section_divided_into_parts):

            """ Работаем с разделом видео, который поделен на части """

            def get_names_parts(browser):

                """ Получаем название каждой части """

                def get_parts_bs(page):

                    """ Получаем имена частей bs """

                    all_parts = page.find('div', {'class': 'ps-content'}).find('ul').find_all('li', recursive=False)

                    return all_parts


                def check_status_element(part):

                    """ Проверяем есть открыта ли часть """

                    result = part.find('ul')

                    if result: return 'Нажать'
                    else: return 'Не нажимать'


                # ВЫШЕ ОПРЕДЕЛЕНИЕ ФУНКЦИЙ

                done_names_parts = []
                page = self.convert_to_bs(browser)

                parts_bs = get_parts_bs(page)
                names_parts_selenium = browser.find_elements(
                    By.XPATH,
                    '//div[@class="ps-content"]/ul/li/a/div[1]'
                )

                for (part_selenium, part_bs) in itertools.zip_longest(names_parts_selenium, parts_bs):

                    self.move_to_element(browser, part_selenium)           # Перемещаемся к скрытому элементу
                    well_what = check_status_element(part_bs)         # Узнаем нажимать или нет

                    if well_what == 'Нажать': part_selenium.click()   # Оставляем только части

                    done_names_parts.append(part_selenium.text.split('\n')[0])

                return done_names_parts


            def get_list_videos(browser):

                """ Откррываем каждый раздел """

                def get_list_parts_selenium(browser):

                    """ Получаем список частей """

                    list_parts_selenium = browser.find_elements(
                        By.XPATH,
                        '//div[@class="ps-content"]//li'
                    )

                    return list_parts_selenium


                def get_list_videos_selenium(browser, count):

                    """ Получаем спсиок видео """

                    list_videos_selenium = browser.find_elements(
                        By.XPATH,
                        f'//div[@class="ps-content"]/ul/li[{count}]//li'
                    )

                    return list_videos_selenium


                # ВЫШЕ ОПРЕДЕЛЕНИЕ ФУНКЦИЙ

                count = 1
                done_list_videos_selenium = []
                list_parts_selenium = get_list_parts_selenium(browser)

                for part in list_parts_selenium:

                    self.move_to_element(browser, part)    # Перемещаемся к элементу
                    part.click()

                    list_videos_selenium = get_list_videos_selenium(browser, count)
                    done_list_videos_selenium.append(list_videos_selenium)

                    count += 1
                    time.sleep(.5)

                return done_list_videos_selenium


            def merge_data(names_parts, list_videos):

                """ Объединяем данные """

                combined_data = []

                for name, list in itertools.zip_longest(names_parts, list_videos):

                    list.insert(0, name)
                    combined_data.append(list)

                return combined_data


            # ВЫШЕ ОПРЕДЕЛЕНИЕ ФУНКЦИЙ

            names_parts = get_names_parts(browser)
            list_videos = get_list_videos(browser)
            combined_data = merge_data(names_parts, list_videos)

            return combined_data


        # ВЫШЕ ОПРЕДЕЛЕНИЕ ФУНКЦИЙ

        try:  # Если раздел поделен на части

            section_divided_into_parts = browser.find_elements(
                By.XPATH,
                '//div[@class="ps-content"]/ul/li/a/i'
            )

            print(0)
            result = work_with_section_divided_into_parts(browser, section_divided_into_parts)

            return ['Есть части', result]

        except Exception as e:  # Если раздел не поделен на части

            result = browser.find_elements(
                By.XPATH,
                '//div[@class="ps-content"]/ul/li'
            )

            return ['Нет частей', result]


    def rewind_video_to_beggining(self):

        """ Перематываем видео в начало """

        settings_button = pyautogui.locateOnScreen('./images/logo.png')
        button_location = pyautogui.center(settings_button)

        pyautogui.moveTo(button_location[0], button_location[1], .2)
        pyautogui.moveRel(50, 485, .5)
        pyautogui.dragTo(-50, 485, .5)
        pyautogui.moveTo(150, 150, .5)


    def working_with_list_videos(self, browser, data):

        """ Работаем со список видео """

        def check_presence_of_folder():

            """ Проверяем наличие папки, если нет ее - создаем """

            if not os.path.exists('subtitles_of_all_videos'):

                os.mkdir('subtitles_of_all_videos')


        def check_for_files():

            """ Проверяем наличие файлов в папке, если есть - удаляем """

            #folder_path = Path('./subtitles_of_all_videos/*')

            for root, dirs, files in os.walk('./subtitles_of_all_videos'):

                for f in files:

                    os.unlink(os.path.join(root, f))

                for d in dirs:

                    shutil.rmtree(os.path.join(root, d))


        # ВЫШЕ ОПРЕДЕЛЕНИЕ ФУНКЦИЙ

        check_presence_of_folder()    # Проверяем существует ли папку
        check_for_files()             # Проверяем существуют ли файлы в папке
        count = 1

        if data[0] == 'Есть части':

            data = data[1]

            for all_videos in data:

                part_name = all_videos[0]

                for (current_iteration, video) in enumerate(all_videos[1:], 1):

                    self.move_to_element(browser, video)    # Перемещаемся к скрытому элементу
                    video.click()                           # Перешли на следующее видео

                    video_title = '-'.join(video.text.split('\n'))    # Получили название текущего видео
                    video_title = f'{count}-{video_title}'

                    print(video_title)
                    print('video_title')

                    self.start_video(browser)           # Запускаем текущее видео
                    time.sleep(5)                       # Чуть-чуть ждем
                    self.rewind(browser)                # Перематываем

                    subtitles_and_timecodes = self.get_subtitles_and_timecodes(browser)    # Получаем субтитры
                    data = self.converting_data(subtitles_and_timecodes)                   # Преобразуем их в нужный вид

                    self.add_data_to_file(video_title, data)    # Все записываем

                    self.wait(4.9, 5)
                    count += 1

                    time.sleep(.5)

        if data[0] == 'Нет частей':

            data = data[1]

            for current_iteration, video in enumerate(data, 1):

                video.click()                                  # Перешли на следующее видео
                video_title = '-'.join(video.text.split('\n'))                    # Получили название текущего видео
                video_title = f'{count}-{video_title}'

                self.start_video(browser)                      # Запускаем текущее видео

                time.sleep(5)

                self.rewind(browser)

                subtitles_and_timecodes = self.get_subtitles_and_timecodes(browser)    # Получаем субтитры
                data = self.converting_data(subtitles_and_timecodes)

                #translated_subtitles = self.translate_subtitles(data)

                self.add_data_to_file(video_title, data)

                self.wait(4.9, 5)
                print(f'С видео {video_title} под номером #{current_iteration} закончили')


    def start_parsing(self):

        """ Начать парсинг """

        browser = self.get_browser_with_authorized_user()                   # Получаем сконфигурированный браузер для парсинга

        data = self.get_list_videos_to_watch(browser)    # Получаем список видео для парсинга
        print(data)
        print('*' * 20)
        self.working_with_list_videos(browser, data)     # Работаем со списком видео

        browser.quit()
